#include "../main.h"

var Mysql = function(){};

Mysql.prototype = {
	open: function(host, user, pass, db) {
		__c {
			this->conn = mysql_init(NULL)
		}
	}
}

static JSBool
js_mysql_open(JSContext *cx, uintN argc, jsval *vp) {
	trace1("js_mysql_open");
	struct T *x = (struct T *)JS_GetPrivate(cx, JS_THIS_OBJECT(cx, vp));
	
	char *host, *user, *pass, *db;
	
	if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "ssss", &host, &user, &pass, &db)) 
		return JS_FALSE;

	if (!(x->conn = mysql_init(NULL)))
		fatal("Error %u: %s\n", mysql_errno(x->conn), mysql_error(x->conn));

	if (!(mysql_real_connect(x->conn, host, user, pass, db, 0, NULL, 0)))
		fatal("Error %u: %s\n", mysql_errno(x->conn), mysql_error(x->conn));
		
	if (mysql_set_character_set(x->conn, "utf8"))
		fatal("Error %u: %s\n", mysql_errno(x->conn), mysql_error(x->conn));
	
	return JS_TRUE;
}


static JSBool
js_mysql_query(JSContext *cx, uintN argc, jsval *vp) {
	trace1("js_mysql_query");
	struct T *x = (struct T *)JS_GetPrivate(cx, JS_THIS_OBJECT(cx, vp));

	char *q;

	if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "s", &q)) 
		return JS_FALSE;

	if (mysql_query(x->conn, q))
		fatal("Error %u: %s\n", mysql_errno(x->conn), mysql_error(x->conn));

	MYSQL_RES *rs;
	MYSQL_ROW row;
	int i, cols;

	rs = mysql_store_result(x->conn);
	cols = mysql_num_fields(rs);

	jsval f;
	JS_ConvertValue(cx, argv[1], JSTYPE_FUNCTION, &f);
		
	jsval *f_argv=calloc(cols, sizeof(jsval));
	jsval f_ret;

	JS_BeginRequest(cx);
	while (row=mysql_fetch_row(rs)) {
		for(i=0; i<cols; i++)
			f_argv[i] = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, row[i]));
		if(JS_TRUE!=JS_CallFunctionValue(cx, JSVAL_NULL, f, cols, f_argv, &f_ret))
			goto end;
	}
end:
	mysql_free_result(rs);
	JS_EndRequest(cx);
	
	pthread_mutex_unlock(&mux_sql);
	
	*rval=JSVAL_VOID;
	return JS_TRUE;
	
	//mysql_close(conn);
}


/**
 *
 */
static JSBool
js_Curl_init(JSContext *cx, uintN argc, jsval *vp) {
	trace1("js_Curl_init");
	struct T *x = (struct T *)JS_GetPrivate(cx, JS_THIS_OBJECT(cx, vp));
	x->curl = curl_easy_init();
	JS_SET_RVAL(cx, vp, JSVAL_VOID);
	return JS_TRUE;
}



#ifdef PROP
#undef PROP
#endif
#define PROP(type, name) \
	case PROP_CURLOPT_ ## name: \
		trace2("setting property " #name); \
		curl_easy_setopt(x->curl, CURLOPT_ ## name, ARG_ ## type (1)); \
		break;


/**
 *
 */
static JSBool
js_Curl_setopt(JSContext *cx, uintN argc, jsval *vp) {
	trace1("curl_setopt");
	struct T *x = (struct T *)JS_GetPrivate(cx, JS_THIS_OBJECT(cx, vp));
	int opt = ARG_INT(0);
	switch(opt) {
		default: ERR("unknown curl option %d", opt);
#include "curlopts.def"
	}
	JS_SET_RVAL(cx, vp, JSVAL_VOID);
	return JS_TRUE;
}


static JSBool
js_Curl_perform(JSContext *cx, uintN argc, jsval *vp) {
	trace1("js_Curl_perform");
	struct T *x = (struct T *)JS_GetPrivate(cx, JS_THIS_OBJECT(cx, vp));
	if (!x->curl) ERR("curl is not initialized!");

	trace2("finalizing curl initialization");
	
	x->chunk.memory = (char *)malloc(1);	
	x->chunk.size = 0;


	curl_easy_setopt(x->curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);	
	curl_easy_setopt(x->curl, CURLOPT_WRITEDATA, (void *)&x->chunk);
//	curl_easy_setopt(x->curl, CURLOPT_NOPROGRESS, 1);	
//	curl_easy_setopt(x->curl, CURLOPT_FOLLOWLOCATION, 1);

	//curl_easy_setopt(x->curl, CURLOPT_URL, "http://localhost/test");
	
	trace2("before curl_easy_perform()");

	CURLcode ret = curl_easy_perform(x->curl);
	trace2("curl_easy_perform returned %d", ret);
	
	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, x->chunk.memory)));
	
	//JS_SET_RVAL(cx, vp, INT_TO_JSVAL(ret));
	return JS_TRUE;
	
	
/*	
	
	curl_easy_setopt(x->curl, CURLOPT_TIMEOUT, 1);
	curl_easy_setopt(x->curl, CURLOPT_TCP_NODELAY, 1);
	curl_easy_setopt(x->curl, CURLOPT_AUTOREFERER, 1);
	curl_easy_setopt(x->curl, CURLOPT_MAXREDIRS, 10);
	curl_easy_setopt(x->curl, CURLOPT_USERAGENT, "curl");
	x->readyState = 1;	
*/	
}




static JSBool getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp){
	if(!JSVAL_IS_INT(id))
		return JS_FALSE;
	int x = JSVAL_TO_INT(id);
	*vp = INT_TO_JSVAL(x);
	return JS_TRUE;
}


#ifdef PROP
#undef PROP
#endif
//#define PROP(type, name) { "CURLOPT_" #name, PROP_CURLOPT_ ## name },
#define PROP(type, name) { "CURLOPT_" #name, PROP_CURLOPT_ ## name, JSPROP_READONLY | JSPROP_ENUMERATE, getProperty, NULL },


static JSPropertySpec props[] = {
#include "curlopts.def"
	{0}
};


static JSFunctionSpec methods[] = {
	JS_FN("init",    js_Curl_init,    0,0),
	JS_FN("setopt",  js_Curl_setopt,  1,0),
	JS_FN("perform", js_Curl_perform, 1,0),
//	JS_FN("open",   Curl$open,   2,0),
//	JS_FN("send",   Curl$send,   1,0),
	JS_FS_END
};



/**
 *
 */
static JSBool
construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){
	trace1("curl");
	struct T *x = (struct T *)calloc(sizeof(struct T), 1);
	x->curl = curl_easy_init();
	x->obj = obj;
	JS_SetPrivate(cx, obj, x);
	return JS_TRUE;
}



/**
 *
 */
static void finalize(JSContext *cx, JSObject *obj){
	trace1("mysql_finalize");
//	trace2("call");
}



static JSClass __class = {
	"Mysql",
	JSCLASS_HAS_PRIVATE,
	JS_PropertyStub, JS_PropertyStub, getProperty, JS_PropertyStub,
	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize,
	JSCLASS_NO_OPTIONAL_MEMBERS
};




void class_mysql_init(JSContext *cx){
	JSObject *proto = JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, 
		&__class, construct, 0,
		props, methods, props, NULL
	);
}




